﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
#if !WINDOWS_PHONE


#endif

namespace DARE
{
    public class CBasicModel : AModel
    {

    #region fields

#if WINDOWS_PHONE
        protected VertexPositionNormalTexture[] m_vertices;
#else
        protected VertexPositionNormalTextureTangentBinormal[] m_vertices;
#endif
        protected short[] m_indices;
        protected VertexBuffer m_vertexBuffer = null;
        protected IndexBuffer m_indexBuffer = null;
        protected Vector3 m_size = Vector3.One;
        protected Color m_color = Color.White;
        protected Random m_random = CDare.Instance.Random;
        protected PrimitiveType m_primitiveType = PrimitiveType.TriangleList;
        private Texture2D m_texture2d = null;
        private int m_primitiveNum = 3;

    #endregion

    #region properties

        public VertexBuffer VertexBuffer { get { return m_vertexBuffer; } }
        public IndexBuffer IndexBuffer { get { return m_indexBuffer; } }


        public Vector3 Size
        {
            get { return m_size; }
        }

        public Color Color
        {
            get { return m_color; }
            set
            {
                m_color = value;
                m_texture2d = new Texture2D(DARE.CDare.Instance.GraphicsDevice, 1, 1);
                Color[] c = new Color[1] { m_color };
                m_texture2d.SetData(c);
                m_effect.ColorMap = m_texture2d;
            }
        }

        public virtual int Slices
        {
            get; set;
        }

    #endregion

    #region ctor

        public CBasicModel()
        {
            Initialize(null, 1, 1, 1);
        }

        public CBasicModel(string name)
        {
            Initialize(name, 1, 1, 1);
        }

        public CBasicModel(float x, float y, float z)
        {
            Initialize(null, x, y, z);
        }

        public CBasicModel(string name, float x, float y, float z)
        {
            Initialize(name, x, y, z);
        }

        private void Initialize(string name, float x, float y, float z)
        {
            m_name = name;
            m_size = new Vector3(x, y, z);
            Color = new Color(m_random.Next(255) / 255.0f, m_random.Next(255) / 255.0f, m_random.Next(255) / 255.0f);
        }

        public override AModel Clone()
        {
            return this;
        }

        protected void CopyPropertiesTo(CBasicModel otherModel)
        {
            otherModel.Color = m_color;
            otherModel.FillMode = FillMode;
            otherModel.CullMode = CullMode;
            base.CopyPropertiesTo(otherModel);
        }

    #endregion

    #region update/draw

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
            Draw(gameTime, m_node);
        }

        public void Draw(Matrix world, Matrix view, Matrix projection)
        {

        }

        public void Draw(GameTime gameTime, CNode node)
        {
            if (m_show == false || m_vertexBuffer == null || node == null || 
                node.Render3D == null || node.Render3D.CameraMgr.ActiveCamera == null)
                return;
            if ((m_primitiveType == PrimitiveType.LineList) || (m_primitiveType == PrimitiveType.LineStrip))
                m_primitiveNum = 2;
            else
                m_primitiveNum = 3;
            //Slices = node.Render3D.BasicModelSlices;

            // set vertex and index buffers


            CDare.Instance.GraphicsDevice.SetVertexBuffer(m_vertexBuffer);
            if (m_indexBuffer != null)
                CDare.Instance.GraphicsDevice.Indices = m_indexBuffer;

            
            // ??????
            //CCamera cam = m_node.Render3D.CameraMgr.GetCamera("ShadowsCamera");

            //node.Render3D.EffectMgr.SetEffectGlobalValues(ref m_effect);

            // set the matrices
            m_effect.World = Matrix.Identity;
            m_effect.World *= Matrix.CreateScale(m_scale);
            m_effect.World *= m_orientation;
            m_effect.World *= node.WorldMatrix;
            m_effect.World *= Matrix.CreateTranslation(m_offset);
            m_effect.View = node.Render3D.CameraMgr.ActiveCamera.View;
            m_effect.Projection = node.Render3D.CameraMgr.ActiveCamera.Projection;

            // draw
            m_effect.ProcessEffect(node.Render3D);
            
            EffectPassCollection passes = m_effect.Effect.CurrentTechnique.Passes;
            foreach (EffectPass pass in passes)
            {
                pass.Apply();
#if WINDOWS_PHONE
            

                if (m_indexBuffer == null)
                    CDare.Instance.GraphicsDevice.DrawPrimitives(m_primitiveType, 0, m_vertices.Length / m_primitiveNum);
                else
                    CDare.Instance.GraphicsDevice.DrawIndexedPrimitives(m_primitiveType, 0, 0, m_vertices.Length, 0, m_indices.Length / m_primitiveNum);
#else
                if (m_indexBuffer == null)
                    CDare.Instance.GraphicsDevice.DrawUserPrimitives<VertexPositionNormalTextureTangentBinormal>(
                        m_primitiveType, m_vertices, 0, m_vertices.Length / m_primitiveNum);
                else
                    CDare.Instance.GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionNormalTextureTangentBinormal>(
                        m_primitiveType, m_vertices, 0, m_vertices.Length, m_indices, 0, m_indices.Length / m_primitiveNum);
#endif
            }
        }

    #endregion

    #region utils

        protected override BoundingBox GetMinBoundingBox()
        {
            float maxValue = float.MinValue;
#if WINDOWS_PHONE
            VertexPositionNormalTexture[] vertices = new VertexPositionNormalTexture[VertexBuffer.VertexCount];
            VertexBuffer.GetData<VertexPositionNormalTexture>(vertices);

            foreach (VertexPositionNormalTexture vertex in vertices)
#else
            VertexPositionNormalTextureTangentBinormal[] vertices = new VertexPositionNormalTextureTangentBinormal[VertexBuffer.VertexCount];
            VertexBuffer.GetData<VertexPositionNormalTextureTangentBinormal>(vertices);

            foreach (VertexPositionNormalTextureTangentBinormal vertex in vertices)
#endif
            {
                if (Math.Abs(vertex.Position.X) > maxValue)
                    maxValue = Math.Abs(vertex.Position.X);
                if (Math.Abs(vertex.Position.Y) > maxValue)
                    maxValue = Math.Abs(vertex.Position.Y);
                if (Math.Abs(vertex.Position.Z) > maxValue)
                    maxValue = Math.Abs(vertex.Position.Z);
            }
            return new BoundingBox(Vector3.One * -maxValue, Vector3.One * maxValue);
        }

    #endregion

    #region setup

        protected virtual void CreateVertexBuffer()
        {
            //m_vertexBuffer = new VertexBuffer(CDare.Instance.GraphicsDevice, typeof(VertexPositionNormalTexture), m_vertices.Length, BufferUsage.WriteOnly);
#if WINDOWS_PHONE
            m_vertexBuffer = new VertexBuffer(CDare.Instance.GraphicsDevice, typeof(VertexPositionNormalTexture), m_vertices.Length, BufferUsage.None);
#else
            m_vertexBuffer = new VertexBuffer(CDare.Instance.GraphicsDevice, typeof(VertexPositionNormalTextureTangentBinormal), m_vertices.Length, BufferUsage.None);
#endif
            m_vertexBuffer.SetData(m_vertices);
        }

        protected virtual void CreateIndexBuffer()
        {
            m_indexBuffer = new IndexBuffer(CDare.Instance.GraphicsDevice, IndexElementSize.SixteenBits, m_indices.Length, BufferUsage.None);
            m_indexBuffer.SetData(m_indices);
        }

    #endregion

    }
}
